Juiced Up First Person Character Controller Tutorial - Godot 3D FPS

LegionGames
19 May 202310:47

Summary

TLDRIn this tutorial, the creator guides viewers through building a first-person character controller from scratch, integrating features like head bobbing and field of view changes to enhance the game experience. Utilizing Godot's CSG box for prototyping, the character is set up with basic movement and jump functionality. The video delves into coding details, including handling gravity, jump mechanics, and movement direction. It also covers input mapping, camera rotation, and mouse sensitivity adjustments. Additional game juice is added with head bobbing effects using sine waves and sprinting mechanics, concluding with inertia and field of view adjustments for a more immersive gameplay.

Takeaways

  • 🎮 The video tutorial covers creating a first-person character controller from scratch with added 'game juice' features.
  • 🏗️ The process begins by setting up a new 3D scene and using a CSG box for ground prototyping and a character body mesh for the player.
  • 👾 A script is added to the character for basic movement and jumping, which works for both first and third-person perspectives.
  • 💡 Lighting and a world environment are set up with a directional light to mimic the sun for a realistic look.
  • 🔒 The camera is added as a child of a node 3D to prevent 'janky' rotation issues, with a reference to Godot documentation for further details.
  • 📏 Constants for speed, jump velocity, and gravity are defined, with the physics process handling jumps and character movement.
  • 🕹️ Custom input mapping is created to replace default UI actions, allowing for more personalized control settings.
  • 🔍 The tutorial discusses handling mouse input for camera rotation, with sensitivity adjustments and clamping to limit rotation range.
  • 🏃‍♂️ Head Bob effect is implemented using sine waves to simulate the character's footsteps, enhancing the game's immersion.
  • 🔄 Inertia is added to the character's movement to prevent abrupt stops in mid-air, providing a smoother player experience.
  • 🔬 The camera's field of view (FOV) changes dynamically based on the character's speed, adding another layer of realism to the gameplay.

Q & A

  • What is the main focus of the video?

    -The video focuses on creating a first-person character controller from scratch with various game feel enhancing features, also known as game juice.

  • What are some of the game feel features included in the character controller?

    -The game feel features include head Bob, inertia, movement, and field of view (FOV) change.

  • What is the purpose of using a CSG box for the ground in the 3D scene?

    -The CSG box is used for its simplicity and combination with a collision shape, which is good for prototyping.

  • Why is the character body using an old code character body 3D?

    -The old code character body 3D is used because it has a default code template with movement and jumps implemented, which works well for both first-person and third-person control.

  • How does the video handle the lighting in the game scene?

    -The video adds a world environment and a directional light to the scene tree to imitate the sun and ensure proper lighting.

  • What is the purpose of adding a camera as a child of a node 3D?

    -Adding a camera as a child of a node 3D acts as a pivot to avoid janky results when rotating the camera without one.

  • What is the issue with the default UI actions in the character controller code?

    -The default UI actions are replaced with custom ones to allow for more control over the character's movement and interactions.

  • How does the video address the problem of the character not moving in the direction it's facing?

    -The video suggests setting the direction of movement to where the head is facing instead of the character body, as the head is responsible for looking left and right.

  • What mathematical function is used to implement the head Bob feature?

    -The sine wave function is used to implement the head Bob feature, which moves the camera up and down to imitate footsteps.

  • How is the sprinting mechanic integrated into the character controller?

    -Sprinting is integrated by changing the character's speed variable based on whether the shift key is pressed, with separate constants for walk speed and sprint speed.

  • What is the purpose of the inertia in the character controller?

    -Inertia is added to give the player more control over horizontal movement in the air and to ensure a smoother transition when the player stops moving mid-air.

  • How does the video change the camera field of view based on character speed?

    -The video uses a formula that adds a base FOV and a FOV change multiplied by the character's velocity, clamping the velocity to ensure the FOV doesn't become too extreme.

Outlines

00:00

🚀 Creating a 3D Character Controller with Game Juice

The video script begins with an introduction to creating a first-person character controller from scratch, focusing on enhancing the game feel with various features known as 'game juice'. The tutorial covers setting up a 3D scene with a CSG box for the character's body, using a mesh and collision shape for better performance. The character will use an old code character body 3D with a bean shape mesh. A script with movement and jumps is added, and lighting is set up with a world environment and directional light. The character is given a camera as a child node to act as a pivot, and the script explains the importance of this setup for smooth camera rotation. Basic movement and jumping mechanics are implemented, and the script is reviewed to ensure proper functionality, including handling jumps and movement on the floor.

05:02

🎮 Enhancing Player Experience with Head Bob and FOV Adjustments

This paragraph delves into improving the player's experience by adding head bobbing to mimic the character's footsteps using a sine wave function. Key variables such as Bob frequency and amplitude are introduced to control the bobbing effect. The character's movement direction is corrected to align with the head's orientation rather than the body's. Sprinting is added to the character's movement, adjusting the speed based on whether the shift key is pressed. Inertia is introduced to the jump mechanic to prevent the character from stopping abruptly in mid-air, using the lerp function to gradually adjust the velocity. The tutorial also addresses issues with the character's stopping mechanism on the ground, adding a ramp-up effect for more realistic deceleration. Lastly, the camera's field of view (FOV) is dynamically adjusted based on the character's speed, creating an immersive experience that responds to the player's actions.

10:03

🔧 Final Touches and Community Engagement

The final paragraph wraps up the character controller tutorial by addressing the last details and seeking community feedback. The script includes a velocity clamping mechanism to ensure the field of view doesn't become too extreme during high-speed falls. The tutorial concludes with a smooth FOV transition using the lerp function. The creator invites viewers to engage with the project on GitHub and expresses openness to creating a follow-up video if there's enough interest. The video ends with a call to action for likes and comments, encouraging viewers to share their thoughts on the tutorial and suggest additional features for future content.

Mindmap

Keywords

💡First-person character controller

A first-person character controller is a system in video game development that allows the player to control a character from a first-person perspective. In the video, the creator is building such a controller from scratch, which is central to the theme of game development. The script mentions enhancing this controller with various features to improve the game's feel.

💡Game feel

Game feel refers to the subjective experience of interacting with a game, often influenced by the mechanics and aesthetics. The video focuses on adding 'game juice' or features that enhance game feel, such as head bobbing and field of view changes, to make the gameplay more immersive and responsive.

💡CSG box

CSG stands for Constructive Solid Geometry, and a CSG box is a tool in 3D modeling used for creating simple shapes with collision detection, which is ideal for prototyping. In the script, the CSG box is used to create the ground for the game world and to establish basic collision shapes for the character.

💡Node

In the context of game development, particularly within the Godot engine mentioned in the script, a node is an object within the scene tree that represents an element of the game, such as a character or light source. The script discusses adding nodes like 'CSG box' and 'camera' to build the game environment.

💡Head Bob

Head Bob is a motion effect used in first-person games to simulate the natural bobbing of a character's head while walking or running. The video script describes adding this feature to the character controller to mimic the sensation of movement and enhance the player's immersion.

💡Inertia

Inertia in physics is the resistance of any physical object to any change in its velocity. In gaming, particularly in character controllers, inertia can be used to make movement feel more natural by gradually changing the character's speed rather than instantly, as mentioned in the script when discussing airborne movement.

💡Field of View (FOV)

Field of View in gaming refers to the extent of the observable game world that is visible to the player at any given moment. The script discusses changing the FOV based on the character's speed to add a dynamic visual effect that corresponds with the player's actions.

💡Physics process

A physics process in game development is a function that is called every frame to update the state of the game world according to the laws of physics. The script uses the physics process to handle character movements, jumps, and head bobbing effects.

💡Sine wave

A sine wave is a smooth periodic oscillation that occurs in mathematics and physics, often used to model periodic phenomena. In the video, the sine wave is used to create the head bobbing effect by moving the camera up and down in a periodic manner.

💡Lerp function

Lerp stands for linear interpolation, a method of blending two values to find a value in between them. In the script, the lerp function is used to smoothly transition the character's velocity when airborne, adding a sense of inertia to the movement.

💡Godot documentation

The Godot documentation refers to the official guide and reference material for the Godot game engine, which the video is based on. The script mentions a page in the Godot documentation that explains a specific issue with camera rotation and provides a code snippet for resolution.

💡Input map

An input map in game development is a configuration that defines how player inputs correspond to in-game actions. The script discusses creating an input map to customize the actions for the game, such as movement and jumping.

Highlights

Creating a first-person character controller from scratch with enhanced game feel features.

Introduction of head Bob, inertia, and movement FOV change as key features for game juice.

Utilization of a CSG box for prototyping with a simple mesh and collision shape.

Adoption of an old code character body 3D with bean shape mesh for character design.

Optimization through simplified convex collision shapes for better performance.

Scripting for movement and jumps with a default code template suitable for first and third person control.

Setting up a world environment and directional light for realistic lighting.

Camera setup as a child of a node 3D to avoid janky rotation results.

Explanation of Godot documentation and code snippet for camera rotation without a pivot.

Implementation of speed and jump velocity constants with gravity variable adjustments.

Physics process handling for jump mechanics and character movement.

Correction of a mistake in friction implementation affecting player movement.

Custom input mapping for game actions and cursor capture for free movement.

Defining variables for head and camera rotation with sensitivity adjustments.

Use of clamp function to limit camera rotation for a more realistic experience.

Creating a map using CSG boxes with different color materials for visual enhancement.

Addressing the issue of character movement direction in relation to the head's orientation.

Implementation of head Bob using sine waves to mimic character footsteps.

Addition of horizontal head Bob component for more realistic movement.

Adjustment of character speed with sprinting mechanics for varied player speeds.

Fixing jump mechanics to add inertia and prevent immediate stops in mid-air.

Smoothing character movement with lerp function for horizontal control in the air.

Improving the running stop mechanic with a gradual deceleration effect.

Changing the camera field of view based on character speed for dynamic gameplay.

Finalization of the character controller with a complete set of movement and visual features.

Invitation for feedback and potential creation of a second part for additional features.

Transcripts

play00:00

hello and welcome back to the channel

play00:02

today we'll be making a complete first

play00:04

person character controller from scratch

play00:06

with a bunch of features to enhance the

play00:08

game feel also known as game juice these

play00:11

features will include head Bob inertia

play00:13

and movement fov change so let's Dive

play00:16

Right In we're going to create a new 3D

play00:19

scene and call it world for our ground

play00:21

we're going to use a node called CSG box

play00:24

which is basically a simple mesh

play00:25

combined with a collision shape that's

play00:27

good for prototyping our character is

play00:29

going to use an old code character body

play00:31

3D we're going to add a mesh to it by

play00:33

choosing the bean shape and the mesh

play00:35

drop down we're going to create a

play00:37

collision shape from the match by going

play00:38

to this menu and selecting creates

play00:40

simplified convex Collision sibling if

play00:43

we turn off the visibility on the mesh

play00:45

we can see that we end up with this

play00:46

disheveled beam that has less vertices

play00:48

than their original which is good for

play00:50

performance let's add a script to our

play00:52

Bean character bodies get a default code

play00:54

template with movement and jumps

play00:56

implemented which works well for both

play00:57

first person and third person control in

play01:00

order for the lighting to work properly

play01:02

in our game let's add a world

play01:03

environment and a directional light to

play01:05

imitate the sun to our scene tree let's

play01:07

take a closer look at our Bean the last

play01:09

bit of setup we need to do is adding a

play01:11

camera to him and adding it as a child

play01:13

of a node 3D which will act as our pivot

play01:16

if we don't have one and try to rotate

play01:18

the camera we get some very janky

play01:20

results if you're curious as to why this

play01:23

happens I will link to a page in the

play01:25

Godot documentation that explains it

play01:27

really well and also has a code snippet

play01:29

that would let us do it without a pivot

play01:31

now if we start up our game we are able

play01:33

to move around and even jump out of the

play01:35

box but we can't look around just yet so

play01:38

let's get cracking on our code we have

play01:39

the speed and jump velocity constants

play01:42

here the gravity variable is taken from

play01:44

the default project settings which is

play01:46

9.8 screw that it's now 9.8 and the

play01:49

physics process we handle our jump when

play01:51

the player presses space we set the

play01:53

velocity so we're going up and then

play01:55

every tick we lower this velocity if we

play01:57

are not on the floor until the velocity

play01:59

is in the negatives and we are going

play02:02

down at the end of each tick the move

play02:04

and slide function is called which moves

play02:06

around our character depending on this

play02:08

velocity vector and then changes the

play02:10

velocity depending on collisions so when

play02:13

we're about to end our y velocity is

play02:15

negative 4.5 and then bam it's zero and

play02:19

it stays at zero because we are now on

play02:21

the four and are no longer changing it

play02:23

this last code block takes care of

play02:25

movement on the floor it tells us that

play02:27

we should replace the default UI actions

play02:29

with our own which we will do in a

play02:31

second here we get a vector 2 movement

play02:33

Vector from the inputs and change it to

play02:35

a vector 3 so we can multiply by where

play02:38

our character is facing which gives us

play02:39

this movement Direction Vector if it's

play02:42

non-zero which means that we pressed a

play02:44

button we set the velocity components by

play02:46

multiplying the direction vector by our

play02:48

speed this next part has a bit of a

play02:50

mistake in it the intention here was to

play02:52

add friction and swell the player down

play02:54

gradually but as this thread on the

play02:56

Godot GitHub suggests it just sets the

play02:58

velocity to 0 and instantaneously so

play03:01

let's make that clear and the code the

play03:02

next step is adding our own input map we

play03:05

can do this by going into the project

play03:06

settings naming all of the actions that

play03:08

we want to use in our game and setting

play03:10

bindings for them we add our new actions

play03:12

to the code and then see what we need to

play03:14

do we can see our cursor so it's not

play03:16

captured and we can't walk around so the

play03:19

first step then is to get rid of the

play03:20

cursor we can do that in a ready

play03:22

function which runs at the beginning of

play03:24

a scene by setting the mouse mode to

play03:26

captured after that let's define

play03:28

variables for the head and the camera so

play03:30

we can access them easily in the code

play03:32

references to nodes have to be saved in

play03:35

on ready variables and if we want to get

play03:37

the path to them we can just drag them

play03:39

from the scene tree next to actually

play03:41

rotate the camera we use the unhandled

play03:43

input function which is called every

play03:45

time up where it does anything like

play03:47

press a button or move the mouse we are

play03:49

working specifically for Mouse motion

play03:51

events so we check if it's of this type

play03:53

we change the rotation of the head

play03:55

depending on how much the mouse moved

play03:57

relatively multiplied by the sensitivity

play03:59

which we're going to add as a constant

play04:01

here we're keeping the rotation axes

play04:03

separate so we're only rotating the head

play04:06

on the y-axis and the camera on the ax

play04:08

axis to avoid the whole rotation order

play04:10

Mass you'll also notice we're rotating

play04:13

the head y angle depending on relative X

play04:16

distance this is not a mistake but

play04:18

rather just a byproduct of how

play04:20

translating Mouse movement to camera

play04:22

rotation works when we move the mouse

play04:24

left and right we want to rotate around

play04:27

the y-axis which is pointing up and when

play04:29

we move the mouse up and down we want to

play04:31

rotate around the x-axis which is

play04:33

pointing to the side so after putting

play04:35

all of this together we can finally look

play04:37

around our sensitivity might be a little

play04:39

too high and also we can do cart goes

play04:42

with our head so let's use the clamp

play04:44

function which can limit the rotation of

play04:46

our camera to a minimum and a maximum

play04:49

value I'm also getting tired of staring

play04:51

at a white four with nothing on it so

play04:53

let's use a bunch more CSG boxes with

play04:55

different color materials to create a

play04:57

map

play04:59

much better the last thing we need to

play05:01

fix with the basic movement is the fact

play05:03

that we're not really moving in the

play05:05

direction that we're facing this is an

play05:07

easy fix in the code right now when we

play05:09

set the direction of our Movement we are

play05:11

setting it to where the character body

play05:12

is facing instead we need to set it to

play05:14

where the head is facing since that's

play05:16

the component that's looking left and

play05:18

right for us nice now let's juice this

play05:20

game up the first thing that we're going

play05:22

to add is head Bob that will help us

play05:24

imitate the character's footsteps by

play05:26

moving the camera up and down maybe

play05:28

something like this can you guess which

play05:31

mathematical function we can use that's

play05:33

right the function of my emotional

play05:35

well-being while I was waiting for Godot

play05:37

4 to release I can't believe it's here

play05:39

or the Western known sine wave to

play05:41

implement this we are going to need a

play05:43

couple of variables and constants first

play05:46

is Bob frequency which will affect how

play05:48

often our footsteps happen second Bob

play05:50

amplitude which will affect how far up

play05:52

and down our camera will go and finally

play05:55

we will need a variable that we will

play05:57

pass to the sine function that will

play05:59

determine how far along the sine wave we

play06:01

are at any given moment we're going to

play06:03

increment this variable during every

play06:05

tick of the physics process by

play06:07

multiplying a couple of things that

play06:09

affect our head bar first we want to

play06:10

account for Delta or how much time has

play06:13

passed since last tech we will multiply

play06:15

this by the speed of our character since

play06:16

we want to add Bob more often when we're

play06:18

running and finally we want to make sure

play06:20

that we're only bobbing when we're on

play06:22

the four and walking rather than jumping

play06:24

or falling so we will multiply the

play06:27

result by there is on 4 function which

play06:29

converted to a float will either return

play06:31

one or zero we can then assign the

play06:34

position of the camera to the result of

play06:36

the head Bob function that we will pass

play06:38

the T Bob variable 2. let's code this

play06:40

function real quick it will return a

play06:42

vector 3 variable that we are setting

play06:45

the camera position to within the

play06:46

physics process initially this Vector 3

play06:48

is going to be a zero Vector but we are

play06:50

going to assign its y-coordinate to the

play06:52

sine of T Bob times Bob frequency and

play06:55

then multiply that by the Bob amplitude

play06:57

so now instead of going from negative 1

play06:59

to 1 to X sine it will go from negative

play07:01

amplitude to amplitude the result is a

play07:04

pretty good head ball but if you're

play07:06

looking for a bit more realism we can

play07:08

also add a horizontal component to this

play07:10

since our head is also moving left and

play07:12

right when we're walking this time we're

play07:14

going to assign the position X component

play07:16

to the cosine of time or t Bob times Bob

play07:20

frequency divided by two still keeping

play07:22

up multiply this by Bob amplitude as

play07:25

well I think this will look way better

play07:27

for a lot of games now let's add

play07:28

sprinting to make sure that our Bob

play07:30

looks good at different player speeds to

play07:32

do that we'll change what we set our

play07:34

character velocity to and this code

play07:36

block since we now want our speed to

play07:38

depend on whether we press shift or not

play07:41

it has to be a variable so let's create

play07:43

a speed variable and change our speed

play07:45

constant name to walk speed as well as

play07:48

create a new constant called Sprint

play07:50

speed back in the physics process we

play07:52

will run a check on whether the player

play07:55

has pressed shift or not and then set

play07:57

our speed variable to either Sprint

play07:59

speed or walk speed with that all

play08:01

together we can now run like the wind in

play08:04

our game but let's look closer on some

play08:06

other mechanics specifically there's an

play08:08

issue with the jump where we can stop

play08:10

immediately while in the air if we let

play08:12

go of the movement button so let's fix

play08:14

that by adding a little bit of inertia

play08:17

to the game we're going to do this by

play08:19

only giving the player full control of

play08:21

the horizontal movement when they are on

play08:23

the floor when they are in the air we

play08:25

are instead going to interpolate towards

play08:27

the desired velocity using the lerp

play08:30

function which changes our speed

play08:31

incrementally this function takes three

play08:33

variables in this case it's our initial

play08:36

velocity then our Target velocity and

play08:38

the final one as the decimal percentage

play08:40

of the distance between the two

play08:42

variables that we want to cover in each

play08:44

step since our Delta variable is usually

play08:46

around 0.05 multiplying it by 2 would

play08:50

make our current velocity move toward

play08:52

the target velocity by 10 percent each

play08:55

tick now when we let go of the movement

play08:57

button in midair we won't just stop

play08:59

right there you can play around with

play09:00

this value to figure out how much

play09:01

control you want while you're Airborne

play09:03

but I eventually settled on Delta times

play09:06

3. another thing we can do is fix that

play09:08

running stop mechanic that wasn't quite

play09:10

working in the character template just

play09:12

ramp up a little how fast we come to a

play09:14

stop here and Bam inertia done

play09:17

there's one last thing I want to do to

play09:20

juice this character controller up and

play09:22

that's changing the camera field of view

play09:24

depending on character speed for this

play09:26

we're going to need two constants the

play09:28

base fov which you could change to a

play09:30

variable if the player can set the fov

play09:32

on your game as well as fov change which

play09:35

will multiply by our speed and add to

play09:38

our base fov and the physics process we

play09:40

will be setting a local Target fov

play09:43

variable to this equation which is base

play09:45

fov plus fov change multiplied by

play09:48

velocity the reason why we want to clamp

play09:51

our velocity is to make sure that our

play09:53

fov doesn't go too crazy when we're

play09:55

falling when our velocity reaches super

play09:57

high numbers so let's create a velocity

play10:00

clamped variable which will set to the

play10:02

result of the built-in quam function and

play10:04

restrict it to the minimum of 0.5 so

play10:07

that we don't change that for V when the

play10:09

velocity is super low and a maximum of

play10:12

running speed times 2. after that we'll

play10:14

use our favorite lerb function to set

play10:17

the camera for movie smoothly every tick

play10:19

of the physics process again the first

play10:21

parameter is their original value the

play10:23

second is the target value and the third

play10:25

is the decimal percentage distance that

play10:27

we want to cover and with that our

play10:29

character controller is complete the

play10:31

link to the GitHub project will be in

play10:33

the description so you can start where I

play10:35

left off I might make a second part for

play10:37

this controller if you guys want me to

play10:38

add any specific features to this and if

play10:41

there's enough interest if the video was

play10:43

helpful drop a like and let me know what

play10:45

you think

Rate This

5.0 / 5 (0 votes)

Related Tags
Game DevelopmentCharacter ControllerFirst-PersonGodot EngineGame JuiceHead BobInertiaMovementFOV ChangeTutorial