SDFPSC Progression from Version 2.5 to 3


Hello, 

SDFPSC Developer here! Checking in for another write up. Today I am going to look at SDFPSC and its features and go into what's changed, changing, or will change. I wanna share some of the work progress and thought process that accompanied it. If you want a list of what's new or has changed then scroll to the bottom. I'll have a list down there but instead of just spelling it all out I wanna start to go through a little at time first.. Sorta how you have to do when your actually coding and putting it all together.. 

Now there are a lot of features that are new and a lot that are still emerging as the project gets more involved but at its heart SDFPSC is a simple First Person Controller.. I set out to build one from scratch that, I believe, has more features, performs better, and is easier to understand than the default Character Controller that comes packaged with Unity (my game engine of choice).. and I'm sure Unreal is about the same..

Unity's Character Controller is not bad, but it's not exactly great either.. It comes out of the box with basic movement: Move, Walk, and Jump.. It also has HeadBob, a FOV kick while running, and the best of all, Footsteps! I'm not gonna give away what features are out in the SDFPSC yet but Footsteps are something I seemed to have procrastinated about the most so far.. But before we get to footsteps the character should actually move well enough to actually deserve them.

Fixing The Jitter!

I can't remember whether it was Unity's First Person Character Controller or their First Person RigidBody Controller. Perhaps both. Jittery movement was a thing. It didn't make you feel like your frames were dropping but it definitely looses that smooth feeling that I am going after..  This was not very obvious unless you were aware of it.. To see it the best you find, preferably, a tall object in your game and while remaining facing it side step in a circle around the object.. You'll notice some spazzing and jitterying that is not very obvious in other places.. In Unity Game Engine there are too main loops that run in your code.. An update loop and a fixed update loop. Still kinda clueless about their differences. I remember lots of times people would say "don't move your character in the update loop" The fixed update loop is where you move because that's the update that involves physics.. And yes this is true.. BUT my controller is not a RigidBody.. It does not experience forces from the physics system.. Anything that acts on my controller is emulation physics that I have to manually program. After some testing and switching my code between the loops I officially stuck it in the regular update and it's there to stay as long as it continues to move super smooth!

Fixing the Pogo Slopes

Unity's Controller is nice because it handles stairs and slopes right out of the box.. Stairs work perfectly but slopes not so much... RigidBody controllers use physics and navigate slopes pretty well but the major downside is that it can not handle steps.. The Character controller on the other hand does both but since it doesn't use the physics engine to stay in place it tends to act a bit weird on slopes...


The Character controller has to apply its own downward forces to stay grounded. It need's to know whether it's touching the ground for this, as well as other things like Jumping. ( you only want to jump if the controller is grounded ) The ground check is at the bottom of the Capsule Collider and I'm not totally sure how Unity does there's but it's most likely a Spherecast, Raycast, or maybe even just a primitive trigger collider.. In this example i'm just using a Raycast since it's easier to visualize.. The ray projects downward below the player and has a certain Range.. If it collides with anything ( the ground ) within that Range It can know that it's grounded.. otherwise it will know it's in the air.. Then certain forces can be applied.. Such as while your in the air you want gravity in affect but whilst on the ground you want it to be near 0.. (That way you are not building up more and more gravity so that when you step off of a ledge you don't go flying downwards at 50x the force of gravity.. And these forces are exactly what messes with the controllers ability to smoothly navigate slopes...


You can see here how the ground check is touching the actual ramp and therefor will trigger the Is Grounded boolean.. Now lets run through them.. On Ramp A the incline isn't very steep. These don't tend to be a problem. You can walk up and down them, and even sprint and most of the time you'll be fine.. Ramp B is pretty steep but not enough to where it'll max out our maximum climb angle.. This is the ramp where the problem becomes evident.. On the way up everything is fine.. The bottom of the capsule is being pressed into the ramp and forces it up.. But hopefully you can picture how the Green Raycast will stay in contact with the ramp... A and B both check out.. Ramp C is the culprit in this example.. Same as Ramp B but when you travel down something happens.. If you travel slow enough you might not notice anything. It will descend and reach the bottom. But if you travel a little faster it becomes obvious. If you sprint it becomes blatantly obvious.. What happens, basically, is that you're moving too fast for Gravity to keep up.. Imagine you're at the top.. You run forward and you move 1 unit over to the left.. You should have moved 1 unit to the left and 1 unit down.. But this isn't smooth at all.. You will walk out onto thin air and as soon as the next frame loads the engine's like, "oh snap! you actually should be down here!" and it will abruptly snap you to the ground.. Now repeat this all the way down the slope.. That's the "POGO" I put in the slopes.. 

I went on and discovered another issue I had that stemmed from the same problem.. As I said earlier, the Jump works off of the ground check. You shouldn't be able to jump up off thin air, so we need to be grounded.. The "POGO" effect  screws up the ground check and, in turn, the Jump mechanic.. When running down the slope you watch yourself  bounce down the slope but in the code there's the ground check going crazy as well. You're Grounded! Nope You're Not! Oh Yes You Are! Nope, Yes, Nope, Yes.. With this check flicking on and off so much whenever you're going down the slope if you decide to jump there's a 50/50 chance you even can.. Unacceptable to me..

 To fix this issue, I thought of many different ways and even experimented with a few.. Needless to say that fixes in my head panned out a lot better than when I actually tried to implement them...  A few examples of what doesn't work is... making the RayCast longer so it doesn't lose the ground going down the slope.. problem is when you go to jump you never jump high enough to break contact with the ground so you stay stuck to the floor.. A better Idea was to just add more gravity to force you down to the ramp.. This actually does work but as soon as you step off of the edge that increased gravity just shoots you towards the ground.. That idea seemed to be on the right path so It's the one I chose to fix this issue, only with a few tweaks...

The Pre-Fix Gravity

First off, the way my controller works for the gravity is this: The simulated gravity is the same as actual gravity and keeps building up if it's left on its on and while grounded it might actually build up enough to force you through the geometry of the world... We don't want that so when on the ground we should stop that build up of gravity. On every frame it checks to see if its grounded and if so, it disables the regular gravity and just continuously sets it to 1 or 2.. (could be 0 but i was afraid of floating away :D) When the player jumps all the gravity is set to 0. This allows the player to even get off the ground and actually separate the ground check from the ground.. Once that happen's you are in the air and once again gravity goes to normal (9.8).. Your fall gradually speeds up until you hit the ground.. Now the ground check is active again and gravity is back to the lower 1 or 2..

The Post-Fix Gravity

Looking at the player and you know that there is already a RayCast aimed downward letting us know whether we are grounded.. Whether or not we're grounded is still going to be useful but RayCasts can do more than one thing.. So far it's just returning any collider that it touches.. We also need to know when we are on slopes so we can adjust our gravity how we want it when we want it to make slopes smooth as flat ground.. To find out whether we are on a slope its pretty simple.. The actual plane of the ground that you walk on and any 3d object really, are made of Faces.. A raycast has a useful ability to return the Normal of that Face.. Which sorta just means what direction that face is pointed.. Flat ground returns 0 degree's and a slope will return w/e angle that slope is.. So with the Ground Check checking for our ground and letting us know what type of ground we are on we can simply add another Gravity value that will help us stay glued to that slope..


So now we have 2 checks: GroundCheck (true or false) & Surface Angle ( 0 -180 ).. We already have our grounded gravity and our normal gravity.. Using these 2 checks and a third gravity we can get smooth slope travel and a reliable Jump register.. I used a value somewhere between the two.. In this Diagram you can see how the gravity is changing as the player travels up / down/ and falls off the other side of the ramp onto the ground!

This was the biggest issues that I had with other controllers and the first I tried to fix. Starting on the controller knowing my biggest pet peeves are out of the way made it so much better to work on..

Version 1.0 was unreleased because of how bare-bones it was but most of the foundation of the controller was structured in this version. First was basic input, movement, and camera control. Nothing too crazy but features that would and still are receiving the most attention. I was once told to focus on getting the essentials of your project squared away and everything built up around it will have that same solid feeling. After the normal movement ( Walk ) was in place it was time to add ( Sprint ) At this time it was simply one speed as you walked and a higher speed as you held down shift to sprint..  I knew I wanted so holding a weapon would slow your movement speed so before I dove into the other mechanics I got to coding and quickly came up with a script that would automatically adjust your movement speed ..  

  • While "Walking" you would move at ( Normal Speed )
  • While "Sprinting" you would move twice as fast.. or ( Normal Speed x 2 )
  • While "Weapon is Equipped" you move half as fast.. or if Waking ( Normal Speed x 0.5 )

Version 2 was released with some additional features that weren't exactly finished.. 

  • Jump
  • Crouch
  • Slide

The Jump!

Coding the jumping was pretty fun and with a better ground detection than when I started it felt smooth and responsive.. After adjusting and fine tuning the jump strength, gravity, and the custom smoothing that I added so you wouldn't land so jarring it still wasn't something that I believed was better than the Standard Character Controller. While going over ways to improve it I remembered something about Jumps in certain games that I really appreciated.. I always enjoyed when games have a jump that felt like it had weight to it.. Currently my jump was lacking.. You didn't feel any momentum and the control while in the air was the exact same as on the ground.. If you jumped at full speed and let go of all the keys in the middle of the arch of the jump you would stop immediately and fall straight down.. You could jump backwards and switch your keys and have the player change his direction in mid air! Game's don't have to be and shouldn't be hyper realistic but this floaty, highly maneuverable jump of mine wasn't cutting it.. So, knowing my end goal I got started finishing up the last of the simple mechanics of my controller.


In this example the top platform is just a character walking. Starting on the Left and holding " W " it walks to the end and then pressing " A " it walks backwards towards the middle.. On the bottom platform it's the same character but this time halfway through its Walk it jumps at the end of the platform and just like the above example after going forward a second, by pressing " A " it immediately stops and backs up.. They both act identical and they should because its the same character using the same input only the bottom example doesn't play nice with physics... 

The code behind the movement isn't too complicated at all and I can explain it a little more simply.. 

Here you can see the generalization of how movement works.. ( at least on my controller ) . .

  • Input.GetAxisRaw("Vertical"); will grab the input from the player every frame.. If on a keyboard "W" returns 1 and moves the player forward along its local axis. "S" will return -1 and move the player backwards along its local axis.
  • Input.GetAxisRaw("Horizontal"); does the same thing but returns it for the left and right axis.
  • If using a joystick or a controller it will return a decimal number between -1 or 1 depending on where the analog sticks are..
  • In my script there is a GetInput(); function thats called every frame to get this input. It then assigns it to a variable named Movement to be used later.
  • Then after a few other functions are run the player is ready to move.. FinalMove(); is also a function of mine that gets called and then uses the Movement variable to send the movement to the controller.

By spreading it out like this we can see why our player is so nimble while in the air.. The movement gets read every single frame so we can easily move our player around the X and Z axis regardless of being grounded or in the air.. My first Idea was to only get Input while the player is grounded but quickly learned that as soon as you jump your no longer reading the input its set to zero and you just stop dead in your tracks and fall down.. 

Soon I had an idea that might work.. I made another function to get input just like the one I already have but this time I called it AirInput.. and renamed my old input to GroundInput. While grounded i'll be using GroundInput and while jumping I can use AirInput..  Sounds simple but this gave me a nice hard time to implement it.. First I got it all coded up and had my GroundInput normal and my AirInput divided in half that way you have some control of your jump but no where near what it was.

We'll that failed. When you jump everything worked like it should but nothing like I expected.. First you lose all your movement from the ground just like before. You do instead have AirInput but that's only half of what the ground input was and as soon as you went airbourne whatever movement you managed to get outta the controller had to start from a dead crawl.. 

After a few hours or reflection I figured it out.. You do only get your input from either AirInput or GroundInput depending on whether you are grounded but I had been also changing my movement to only take in the appropriate Input and I needed to somehow use the last input I had from when I was grounded in order to carry through the jump.. I ended up having the Movement Variable using both Inputs at the same time and adding them together.. 

When grounded it works like normal.. Getting input every frame and at normal speed... When in the air its only updating the AirInput but since the Movement is also added in with the GroundInput it uses the last value assigned to GroundInput and continues adding the AirInput onto that until its grounded.. Where it goes back to normal!

Now my Jump feels like a jump.. If you run and jump and let go of all the buttons you will continue to move through the air like you normally would.. If you jump and miss a ledge by a few inches you should have just enough Input coming through the AirInput to help you land correctly!

The Crouch!

Before the slide must come the crouch! This one is pretty simple also but as usual, it being my first time trying to get something to work from scratch it took probably a few too many hours and a little too much frustration to get it to work... 


Upon looking around I saw a few people that did it like " A " It appears to make half the player sink into the floor.. I'm not sure about that and wasn't eager to even try to figure out how.. Upon doing my own experimenting I found that the Component that controls the actual collider of the controller only has 3 parameters, 

  • Height
  • Radius
  • Center

Thinking this is gonna be gravy I got to work. First I tried a nice and simple approach, just scale the thing..  Yea that worked terribly. Later I rigged up a script to change the Height from 1 to 0.5 whenever the control key is held down.. It indeed changed the height of the controller but I got something resembling " B "  Not sure why yet but, I saw what was going on..  The controller is the basically the parent to everything that is the player.. The weapons, the camera, the hit boxs, etc... It changed the size but none of the components moved with it.. This resulted basically like a floating head.. You could walk under objects and clear them but the camera would just clip right through.. 

Soon enough I found that I needed to also change the center.. And it's touchy.. It needs to be at an ideal location or else the scaling of all the children items seems to get messed up and something with the movement if i rememeber.. I got it working and ran into another problem.. It was just too fast.. It was instant and it didn't scale the size of the controller towards the floor the top and bottom of the player came towards the middle and for a few seconds levitating the player before it feel to the ground.. Not what I wanted..

Finally I came up with a solution to use something called Lerp .. which basically takes two numbers and smoothly moves from one to the next.. I found the values for a standing player and the values of a crouching player and assigned them their own variables to make it easy.. now basically  it says 

  • If crouching then move character controller from standing towards character controller crouching
  • If not crouching then move character controller from crouching towards character controller standing

Then one last thing.. After I got the coding working I noticed it was really jerky and it made the camera glitch the visible background.. After staring into space for a while I realized if there was a better way to do it I didnt know it and I just sat there and did some trial and error with the Lerp speeds until it changed from standing size to crouching size fast enough to look correct but slow enough to appear that it's actually crouching and not imploding at chest height and falling to the floor! With the crouch we also have our 4th movement speed.. When crouched you only move 1/4 of the speed you walk..

And now that we have a crouch, we can build ourselves,

The Slide

In version 2 there was a slide already implemented but it was very janky.. It did what it needed to do but had to go through revisions down the road.. One certain thing in particular but we'll get to that..

We now have a crouch but while sprinting and hitting the crouch button it slows to the crouch speed and that's about it.. That's fine while walking but if we are sprinting we need to slide!!! So lets get to figuring this one out.. First thing is pretty simple.. We make two different conditions so that if we are running and hit the crouch we slide but if we are walking and hit the crouch we simply crouch.. On doing this I realized that it's hard to hold Shift to run and hit Ctrl to slide so I made a decision to change the run style.. It now has the toggle sort of run.  After messing around with it I now have it so if you hit Ctrl and you are walking you will begin to sprint.. If you release the button you will still continue to run.. To stop the run I programmed 2 more things...  If you are running and let off the "W" key you will no longer be running.. And if your running and your current speed drops below a certain point you will go into a walk.. ( This is partly due to what we do with the slide later )

Thinking about a slide, I imagine you still want to look around, and that's to keep because the Camera Look is separate from the player. We also want to keep our momentum and be able to control it a little.. Sounding exactly like how I just did the jump I started just recycling my code and eventually came up with something that slides! When you begin the slide it takes the GroundInput and uses the X and Y vectors to slowly Lerp them to Zero.. While this is going on it's skipping over the GroundInput as long as your sliding.. It uses your last speed and direction, locks that in, and lets you slide until you stop.. Unfortunately at first you never stopped.. You could slide around forever and even up steep hills!! The Lerping fixed this.. You now eventually slowed down.. After tuning it a bit I started to like the way it felt but there was one problem.. Once you started the slide once it ended you were locked to the ground.. Your input was now a constant Zero..

To fix this once you started sliding an If statement begins checking the speed of your movement.. If your movement reaches low enough to be the original crouching speed the function will just set a boolean to not be running and the loop is broken and you begin to crawl.. Now with that set up you can also start a slide BUT if you stand up before you reach that transition then you'll stand and still be in the running state! Pretty happy that worked out so easily.. 

At the end of v2.5 we have:

  • Basic Movement
  • Walk, Sprint, and Crouch Speeds
  • Equipped or Unequipped Speed Multiplier
  • Jump that maintains Momentum
  • A Crouch that can be used to Crouch Jump, or Slide

Going into v3 we have:

  • Jump Height Modifier ( will cover in next DevLog )
  • Climbing ( will cover in next DevLog )

!! VERSION 3.25 Is Now Downloadable !!

 It's the most feature rich version yet and contains a Test Scene that has somewhat of an actually goal is able to be played through from start to finish. Including Locked Doors, Keys, Primitive Enemies, Gun Play, and all the Player Mechanics.. Go to the Main Page and download it and give it a try.. Feel free to find bugs, glitches, mechanics in need of adjustments, or whatever else.. Give your opinion, tips, requests, critiques, and etc etc in the comment section!!!

There's plenty more to come and existing mechanics are always being refined and tuned.. Download it yourself to see but if not here's a list of some of the features that are included in the 3.25 version:

  • Walk
  • Sprint
  • Jump
  • Crouch
  • Slide
  • Climb
  • Crouch / Jump
  • Footstep SFX
  • Slide SFX
  • HitScan Weapon
  • Projectile Weapon
  • Gun Muzzle Flash
  • Gun Ejected Shells (real physics objects)
  • Impact Effects
  • Bullet Impact Physics Forces
  • Crouch and Aim Down Sights
  • Standing Aim Down Sights
  • HipFire
  • Slide while HipFire
  • Frag Grenades that have physics force explosions
  • ..that cause blast damage to enemies
  • ..that trigger nearby explosives
  •  ..that can be triggered by gunfire
  • EMP Grenades that disable nearby electronics
  • ..that doesn't cause damage
  • ..that doesn't cause physics forces
  • Gun and Knife Melee
  • Procedural Weapon Sway
  • Inspect Animations
  • Holster for equipping and stowing weapons
  • Camera Look
  • Camera Zoom ( for ADS )
  • Camera Shake ( 3 intensities )
  • Camera Breathing Effect
  • Player Health
  • ..takes regular damage
  • ..takes explosive damage
  • ..has player death state
  • Player Inventory
  • ..keeps inventory of items
  • ..keeps track of ammo in weapons
  • Player Interaction
  • ..can open doors
  • ..can interact
  • ..can pickup items
  • ..can investigate
  • Explosives effected by grenades and gunfire
  • ..use real physics forces
  • ..cause damage
  • ..trigger other nearby explosives
  • Blast door and terminal lock with 3 different key cards
  • Regular door lock can be short circuited by gunfire
  • Final door can only be unlocked once all enemies are dead
  • Key Pickups
  • Health Pickups
  • Ammo Pickups
  • Weapon Pickups
  • Grenade Pickups
  • Powerups, Secrets, etc Pickups
  • Enemy Chain Gun Turret
  • ..can be disabled for 5 seconds with EMP grenade
  • ..can target and follow player when near
  • ..damaged by grenades
  • ..causes explosion on death
  • Enemy Explosives
  • ..will explode other explosive enemies
  • ..seeks out player to inflict blast damage
  • Wandering Enemy Guard
  • ..becomes rag doll when killed
  • ..shaded outline damage indicator
  • ..blood hit effects
  • ..has headshot damage and can lose helmet
  • Dynamic cross hair
  • ..hit marker for connected shots
  • ..fades to invisible while sprinting
  • ..changes to red if targeting enemy
  • Enemy Counter / Secret Counter
  • Health UI w/ blood hurt screen effect
  • ..Tracks Health Points
  • Screen Fader for changing scenes
  • Weapon UI that displays weapons, ammo, and holstered status
  • Inventory UI that displays keys, secrets, etc
  • Status Notifier for displaying items picked up or helpful instructions or messages
  • MainMenu
  • PauseMenu
  • DeathScreen
  • VictoryScreen
  • MORE COMING SOON

[ This project is still in development and as such might have bugs, glitches, and crashes.. The features may not be fully finished and the ones that are may still be changed and modified further down development.. some features are simple or not much worth discussion but lot's of the features are still ongoing from previous versions and have been brought up in the DevLogs.. Lots of the more important features are still worth discussion and will be covered in later DevLogs!!  ]

Until then, check out and enjoy my unfinished SDFPSC v3.25!!

Cheers,

The Developer



Files

SDFPSC v3.25 172 MB
Dec 18, 2019

Get SDFPSC

Leave a comment

Log in with itch.io to leave a comment.