Instead of a timer to make sure you don't immediately start wallrunning, a better option would be to have a boolean canWallRun, and then only set that to true when the character is above a certain height from the floor they just left. You can do this with a simple raycast downwards. To add realism, you can also add an additional check in that boolean, to see if the player's velocity is above a certain value, since no game feels great when you can just run on a wall from stand still (though that is preference, it's not a requirement to add obviously). And as Dender said, you could just add a boolean "useGravity" and set that to false when you're on the wall, and set your actual gravity to only work when useGravity is true. Then when you're on the wall, you can add a custom gravity (for instance, wallGravity) that is lower. Then when you're off the wall, set useGravity back to true and normal gravity is used again. Timers are really not a good idea to use in most cases imo for games.
Wouldn't it be better to enable wall running only after the player has reached the max height of their jump OR past a velocity threshold, because of the situation where you're jumping/falling down from a platform attempting to begin a wall run on a wall below you?
For anyone who wants a wall jumping mechanic here is the code for that. I will warn you I changed the logic of the wall_run method just a tiny bit for my liking. I added an "if not jumping condition" and switched up the wallrunning boolean. Note this code does not have a wall running timer as I did not want one but the logic for that is already in this vid :) code : ``` extends KinematicBody export var speed = 10 export var acceleration = 5 export var gravity = .98 export var jump = 30 export var walljumpforce = 170 export var walljumpheight = 150 export var mouse_sens = 0.3 var multiplier = 1 export var dec_mouse_sens = .2 onready var head = $Head onready var camera = $Head/Camera var velocity = Vector3() var camera_x_rotation = 0 onready var wall_normal = Vector3() var direction = Vector3() var wallrunning = false func _ready(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _input(event): if event is InputEventMouseMotion: head.rotate_y(deg2rad(-event.relative.x * (GlobalGameSettings.get_sensitivity() * GlobalGameSettings.get_dec_sensitivity())))
var x_delta = event.relative.y * (GlobalGameSettings.get_sensitivity() * GlobalGameSettings.get_dec_sensitivity()) if camera_x_rotation + x_delta > -90 and camera_x_rotation + x_delta < 90: camera.rotate_x(deg2rad(-x_delta)) camera_x_rotation += x_delta
func wall_run():
if !is_on_floor() and Input.is_action_pressed("move_forward") and is_on_wall(): if not Input.is_action_just_pressed("jump"): velocity.y = 0 wall_normal = get_slide_collision(0) yield(get_tree().create_timer(0.1), "timeout") direction = -wall_normal.normal * speed wallrunning = true
func _process(delta): if Input.is_action_just_pressed("ui_cancel"): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
func _physics_process(delta):
var head_basis = head.get_global_transform().basis direction = Vector3()
wall_run() if !is_on_wall(): wallrunning = false if Input.is_action_pressed("move_forward"): direction -= head_basis.z
elif Input.is_action_pressed("move_backward"): direction += head_basis.z
if Input.is_action_pressed("move_left"): direction -= head_basis.x
elif Input.is_action_pressed("move_right"): direction += head_basis.x
I tried reducing the gravity when the player is touching the wall, but it makes the player jump extra high due to the reduced gravity. Any idea how to fix that?
@@crepuscularcrepe you can use different move_and_slide for wall running and pass a different gravity value to it, that way you will not break anything
Your videos has been the main thing that keeps me going in godot. No need for 1.5x speed with this pacing XD. Could you do a video on high level networking for multiplayer?
I have different approach - using raycasts to the sides and without need to use more physics frames. You can check GitHub repository - /nezvers/Godot_Public_Examples/tree/master/3D_FPS_controller It was more like testing ideas on mechanics (also Borderlands3 style ledge jump and crouching)
Hows it working out for you? I was thinking about doing something similar, but I was worried using only one raycast on each side would be too unreliable
@@garbaj It's me and I have a preview video of it on this channel. That's why I shared a repository link for you to check out in detail. You can use force_raycast_update( ) when it's needed, so it's reliable as your use case. I used it as basic as possible to get the wall run, but idea is to count connection as long the player is close enough and has an angle in a certain range (using dot product). I'm working on 2D action platformer state machine to carry it on that FPS controller later. So I could make all kinds of mechanics without spaghetti code. Propper way would force the controller face forward + give some force against the wall but allow look around (in a certain range) and kick off in that direction if the player wants.
Thanks for replying. I figured the cleaner method would require some math. Unfortunately, I don't understand math enough to take advantage of it, hopefully one day I'll be able to.
@@garbaj I'm not that good at math too. 99% for me it's +, -, *, /. It took a bit of time to understand dot-product and still trying to fully understand cross-product. blog.wolfire has great explanation for "blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-2/". The maker of Overgrowth.
Cool, I made wall running by just halving gravity when on wall. Works well and keeps the movement curve, will also let you run as long as you wish, but more and more downward :)
I made fps tps controller and i made the wall jumping based on your's but there is a problem That is when the wall ends the charcter flys to the oppiste go the wall normal how could fix it
Subscribed to your channel last week Your video is easy to understand for person who dont have any programing experience like me Thanks Hopefully you will make animation tutorial *sorry for my bad english
this can be better if we check if the player is falling, if it is, activate the wallrunning script by changing its gravity, so it will trully slide, without a timer, becouse that makes it feel stiff and un-smooth, another thing you can do, is set a "sprint" button that can change the velocity of the player, if the player is falling, while hitting a wall, and also sprinting activate the wallrun, this lets the jumo key free to use, so we can make a jump off the wall feature, i hope you can get what im saying XD
I found if you use an *if statement* to check if your *Y velocity* is > 0 and use that to reduce gravity while only on a wall, you get a nice wall slide effect that only takes place after the apex of your jump which is only a few lines of code away from being a wall jump. I'm new to coding, but, if I'm understanding dot products correctly, could you use a dot product between the camera (or character) direction and the wall normal to determine whether you slide on the wall or run along it?
Hello @Garbaj Nice video, been following your channel because of your awesome short and informative videos about game play concepts. I just had a question on how I would make this into only some walls are allowed to wall run on. So far any wall that has a vertical face, you can wall run on. I have thought on using Collision Masks and layers but that gave me no luck, tried using Area nodes but still no luck, How could I achieve this?
This ought be a whole video in itself, but you could put certain off-limits walls into a “no run” group and using the same get_slide_collision() function, you can check if a wall is in that group or not and only climb on the walls that aren’t in that group
I used raycasts and made gravity be a constant. The one thing that I did wrong though is the way it works. You don't stick to a wall. So when you look away, you fall.
Here's some code for my character, just in case anyone wants to see a different wall run technique: extends KinematicBody onready var camera = $Pivot/Camera var gravity = -25 var jump_speed = 6 var max_speed = 6 var mouse_sensitivity = 0.008 var velocity = Vector3() var jump = false var can_w_run = true var wall_running = false var needs_rot = true var needs_counter_rot = true var can_use_timer = true var wr_speed = 6 var needs_timer_two = true var can_slide = true var sliding = false var needs_slide_rot = true var needs_slide_counter_rot = true var can_use_slide_timer = true var slide_speed = 4 var pulling = false func align_with_y(xform, new_y): xform.basis.y = new_y xform.basis.x = -xform.basis.z.cross(new_y) xform.basis = xform.basis.orthonormalized() return xform
func get_input(): jump = false if Input.is_action_just_pressed("jump"): jump = true var input_dir = Vector3() if Input.is_action_pressed("forward") or wall_running: input_dir += -global_transform.basis.z if Input.is_action_pressed("back") and !wall_running and !sliding: input_dir += global_transform.basis.z if Input.is_action_pressed("left") and !wall_running and !sliding: input_dir += -global_transform.basis.x if Input.is_action_pressed("right") and !wall_running and !sliding: input_dir += global_transform.basis.x input_dir = input_dir.normalized() return input_dir
func _unhandled_input(event): if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: if !wall_running: rotate_y(-event.relative.x * mouse_sensitivity) elif wall_running: $Pivot.rotate_y(-event.relative.x * mouse_sensitivity) $Pivot.rotate_x(-event.relative.y * mouse_sensitivity) $Pivot.rotation.x = clamp($Pivot.rotation.x, -1.2, 1.2) func _physics_process(delta):
fall_recover()
if is_on_floor() and !can_w_run: can_w_run = true
if not ($L_RayCast.is_colliding() or $R_RayCast.is_colliding()) or is_on_floor() or not can_w_run: wall_running = false elif is_on_wall() and can_w_run and not is_on_floor(): wall_running = true
if !wall_running: velocity.y += gravity * delta rotation.z = 0 $Pivot.rotation.y = 0 $Pivot.rotation.z = 0 if !sliding: var desired_velocity = get_input() * max_speed velocity.x = desired_velocity.x velocity.z = desired_velocity.z rotation.x = 0 if jump and is_on_floor(): velocity.y = jump_speed elif sliding: var slide_velocity = get_input() * slide_speed velocity.x = slide_velocity.x velocity.z = slide_velocity.z elif wall_running: var wallrun_velocity = get_input() * wr_speed velocity.x = wallrun_velocity.x velocity.z = wallrun_velocity.z if can_use_timer: $WR_Timer.start() can_use_timer = false if needs_rot: if $L_RayCast.is_colliding(): var n = $L_RayCast.get_collision_normal() global_transform = align_with_y(global_transform, n) rotate_object_local(Vector3(0, 0, 1), PI/3) needs_rot = false if $R_RayCast.is_colliding(): var n = $R_RayCast.get_collision_normal() global_transform = align_with_y(global_transform, n) rotate_object_local(Vector3(0, 0, 1), -PI/3) needs_rot = false velocity.y = 0 if $WR_Timer.time_left == 0: can_w_run = false wall_running = false can_use_timer = true
func fall_recover(): if !is_on_floor() and !wall_running and velocity.y < 0: if $Pull_Lower.is_colliding() and !$Pull_Upper.is_colliding(): pulling = true
A few necessary explanations regarding my code: - It isn't strictly limited to wall running; some sections include fall recovery (grabbing onto ledges) and sliding. I decided to leave those in there in case anyone was interested. - $L_RayCast and $R_RayCast are raycasts extending from the center of the player to one unit left and right, respectively. They are used to detect whether a wall is present for wall running. - $Front_L_RayCast and $Front_R_RayCast are raycasts positioned about an arm's length in front of the player at about chest height and extending to the left and right, respectively. These determine (while wall running) whether there is enough space left to continue wall running. This is why you fall off of the wall if you are about to reach the end of it. - $Pull_Lower is yet another raycast; this one is positioned at about eye level and points in the forward direction. $Pull_Upper is a duplicate of this raycast but is positioned slightly higher -- high enough that it is above the character mesh. These aid in fall recovery; if $Pull_Lower is colliding but $Pull_Upper is not, this essentially tells the physics engine, "There is a ledge (rather than a solid wall) for the player to grab onto." - I know that the input side of my code gets a little cluttered. Long story short, if you're not wall running, the code checks for input on A, W, S, and D. If you are wall running, the code ignores input from the keys but behaves as though W is being held -- in other words, it assumes you want to move forward. This makes sense; moving sideways would cause you to either go inside the wall or fall off of it, and moving backwards would realistically mean losing momentum. I know this is a lot, so just respond to this comment if you have any questions.
When trying to access the normal in "direction = -wall_normal.normal * speed", I get the error "Invalid access to property or key 'normal' on a base object of type 'KinematicCollision3D'." Does anyone know how to fix it?
the buggy part in the beginning is because im just flying now haha edit: partially fixed it. now you fall when not on the wall but i also want to make it so you can jump on the wall and go onto another
On the github page, click on the green "code" button and download zip. Extract the zip to any place on your computer, then go to your Godot project file folders and drag the files extracted from the zip into the godot project folder
can you make a tutorial for how to make the camera rotate based on the wall you stepping on? i wanna make the camera tilt based on what direction the wall is
so how could you change that time into like a stamina bar im sure its not much different in coding i guess you would have to create a stamina bar obviously then script a call to use that resorce till it runs out? like i get the general idea how that would work but not the exact scripting. im like beyond new and binge watching godot videos making things slowly stick
if input = left or right and forward and not grounded and colliding with wall set timer. timer = gravity + ? y gravity = -y * time if graviity is > 10 gravity = 10
could you please update this for youre improved fps controller for godot 3.2, as I have been trying to get this to work in the improved controller. But I just cant
Your tutorials are gold ! I love them ! In the future, it would be very great if you could figure out how to make a grapple gun in godot ! I search but for now, anything i made dont work :/
umm itn not working from first when i go to a wall my playerf sticks to ground and can jump here is my code extends KinematicBody var speed var default_speed = 15 var sprint_speed = 25 var h_acceleration = 8 var air_acceleration = 1 var normal_acceleration = 6 var gravity = 20 var jump = 7 var full_contact = false var mouse_sensitivity = 0.05 var grappling = false var hookpoint = Vector3() var hookpoint_get = false var direction = Vector3() var h_velocity = Vector3() var movement = Vector3() var graviry_vec =Vector3() var fall = Vector3() onready var head =$head onready var groundcheck = $groundcheck onready var camera = $head/Camera func _ready(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) func _input(event): if event is InputEventMouseMotion: rotate_y(deg2rad(-event.relative.x * mouse_sensitivity)) head.rotate_x(deg2rad(-event.relative.y * mouse_sensitivity)) head.rotation.x = clamp(head.rotation.x, deg2rad(-89), deg2rad(89)) func wall_run(): if Input.is_action_pressed("jump"): if Input.is_action_pressed("moce_forward"): if is_on_wall(): fall.y = 0 func _physics_process(delta):
speed = default_speed
direction = Vector3()
if groundcheck.is_colliding(): full_contact = true else: full_contact = false
if Input.is_action_just_pressed("jump") and (is_on_floor() or groundcheck.is_colliding()): graviry_vec = Vector3.UP *jump
if Input.is_action_pressed("ability"): speed = sprint_speed wall_run() if Input.is_action_pressed("moce_forward"): direction -= transform.basis.z elif Input.is_action_pressed("move_backward"): direction += transform.basis.z if Input.is_action_pressed("move_right"): direction += transform.basis.x elif Input.is_action_pressed("move_left"): direction -= transform.basis.x
i tried this on your adanced fps controller. i just fricking float. if possible make a new wallrun tut so people dont have to mix all of the tutorials and get a glitchy mess
Instead of a timer to make sure you don't immediately start wallrunning, a better option would be to have a boolean canWallRun, and then only set that to true when the character is above a certain height from the floor they just left. You can do this with a simple raycast downwards. To add realism, you can also add an additional check in that boolean, to see if the player's velocity is above a certain value, since no game feels great when you can just run on a wall from stand still (though that is preference, it's not a requirement to add obviously).
And as Dender said, you could just add a boolean "useGravity" and set that to false when you're on the wall, and set your actual gravity to only work when useGravity is true. Then when you're on the wall, you can add a custom gravity (for instance, wallGravity) that is lower. Then when you're off the wall, set useGravity back to true and normal gravity is used again.
Timers are really not a good idea to use in most cases imo for games.
Wouldn't it be better to enable wall running only after the player has reached the max height of their jump OR past a velocity threshold, because of the situation where you're jumping/falling down from a platform attempting to begin a wall run on a wall below you?
Nice video man I hope that the grappling hook tutorial is coming soon
For anyone who wants a wall jumping mechanic here is the code for that. I will warn you I changed the logic of the wall_run method just a tiny bit for my liking. I added an "if not jumping condition" and switched up the wallrunning boolean. Note this code does not have a wall running timer as I did not want one but the logic for that is already in this vid :) code :
```
extends KinematicBody
export var speed = 10
export var acceleration = 5
export var gravity = .98
export var jump = 30
export var walljumpforce = 170
export var walljumpheight = 150
export var mouse_sens = 0.3
var multiplier = 1
export var dec_mouse_sens = .2
onready var head = $Head
onready var camera = $Head/Camera
var velocity = Vector3()
var camera_x_rotation = 0
onready var wall_normal = Vector3()
var direction = Vector3()
var wallrunning = false
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _input(event):
if event is InputEventMouseMotion:
head.rotate_y(deg2rad(-event.relative.x * (GlobalGameSettings.get_sensitivity() * GlobalGameSettings.get_dec_sensitivity())))
var x_delta = event.relative.y * (GlobalGameSettings.get_sensitivity() * GlobalGameSettings.get_dec_sensitivity())
if camera_x_rotation + x_delta > -90 and camera_x_rotation + x_delta < 90:
camera.rotate_x(deg2rad(-x_delta))
camera_x_rotation += x_delta
func wall_run():
if !is_on_floor() and Input.is_action_pressed("move_forward") and is_on_wall():
if not Input.is_action_just_pressed("jump"):
velocity.y = 0
wall_normal = get_slide_collision(0)
yield(get_tree().create_timer(0.1), "timeout")
direction = -wall_normal.normal * speed
wallrunning = true
func _process(delta):
if Input.is_action_just_pressed("ui_cancel"):
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
func _physics_process(delta):
var head_basis = head.get_global_transform().basis
direction = Vector3()
wall_run()
if !is_on_wall():
wallrunning = false
if Input.is_action_pressed("move_forward"):
direction -= head_basis.z
elif Input.is_action_pressed("move_backward"):
direction += head_basis.z
if Input.is_action_pressed("move_left"):
direction -= head_basis.x
elif Input.is_action_pressed("move_right"):
direction += head_basis.x
direction = direction.normalized()
velocity = velocity.linear_interpolate(direction * speed, acceleration * delta)
var gravity_resistance = get_floor_normal() if is_on_floor() else Vector3.UP
velocity -= gravity_resistance * gravity
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y += jump
#
if Input.is_action_just_pressed("jump") and wallrunning:
velocity += wall_normal.normal * walljumpforce + Vector3(0,walljumpheight,0)
wallrunning = false
velocity = move_and_slide(velocity, Vector3.UP)
```
In Godot 4, instead of "yield(get_tree().create_timer(.2), "timeout")", use "await get_tree().create_timer(.2).timeout"
and, instead of a timer node, you can simply just make the gravity a small amount so you slowly fall down as you go to make it a lil more realistic
super mario odyssey works like this!
I tried reducing the gravity when the player is touching the wall, but it makes the player jump extra high due to the reduced gravity. Any idea how to fix that?
@@crepuscularcrepe you can use different move_and_slide for wall running and pass a different gravity value to it, that way you will not break anything
@@crepuscularcrepe no just change the gravity to -1 or smh
@@crepuscularcrepe Old post but I just did this myself. Just make make the gravity normal if velocity.y > 0. That way you get the same jump height.
Very easy to follow and super useful. Thank you!
Glad you found it helpful
Holy crap man you have a video on everything! I'm learning 3D and this is super helpful
Great tutorial!!! We can also tilt our player against the wall to give a better look...
You should never rotate the camera as it will cause motion sickness in players
We should use viewports
Your videos has been the main thing that keeps me going in godot. No need for 1.5x speed with this pacing XD. Could you do a video on high level networking for multiplayer?
I hope to do a multiplayer video one day, once I actually learn how to do it
I have different approach - using raycasts to the sides and without need to use more physics frames. You can check GitHub repository - /nezvers/Godot_Public_Examples/tree/master/3D_FPS_controller
It was more like testing ideas on mechanics (also Borderlands3 style ledge jump and crouching)
Hows it working out for you? I was thinking about doing something similar, but I was worried using only one raycast on each side would be too unreliable
@@garbaj It's me and I have a preview video of it on this channel. That's why I shared a repository link for you to check out in detail. You can use force_raycast_update( ) when it's needed, so it's reliable as your use case. I used it as basic as possible to get the wall run, but idea is to count connection as long the player is close enough and has an angle in a certain range (using dot product).
I'm working on 2D action platformer state machine to carry it on that FPS controller later. So I could make all kinds of mechanics without spaghetti code. Propper way would force the controller face forward + give some force against the wall but allow look around (in a certain range) and kick off in that direction if the player wants.
Thanks for replying. I figured the cleaner method would require some math. Unfortunately, I don't understand math enough to take advantage of it, hopefully one day I'll be able to.
@@garbaj I'm not that good at math too. 99% for me it's +, -, *, /. It took a bit of time to understand dot-product and still trying to fully understand cross-product. blog.wolfire has great explanation for "blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-2/". The maker of Overgrowth.
you think you can help me?
Cool, I made wall running by just halving gravity when on wall. Works well and keeps the movement curve, will also let you run as long as you wish, but more and more downward :)
Im super glad I discovered this niche tutorial!
Nice, glad you found it helpful!
I made fps tps controller and i made the wall jumping based on your's but there is a problem
That is when the wall ends the charcter flys to the oppiste go the wall normal how could fix it
That's the shit! Great job man :)
I know you've been asking for a wall running tutorial, hope it was helpful in some way
Subscribed to your channel last week
Your video is easy to understand for person who dont have any programing experience like me
Thanks
Hopefully you will make animation tutorial
*sorry for my bad english
Thanks! I'm glad my videos are helping you
On Ur next tutorial on weapons, you should add on how to make secondary weapon and how to switch between weapons in game.
Love these tutorials man, absolutely awesome 👍 👍 👍
Thank you!
How do u import the files??
(Great tutorial man keep up the work)
also, how will i be able to make it so the cam rotates a little to simulate it better
this can be better if we check if the player is falling, if it is, activate the wallrunning script by changing its gravity, so it will trully slide, without a timer, becouse that makes it feel stiff and un-smooth, another thing you can do, is set a "sprint" button that can change the velocity of the player, if the player is falling, while hitting a wall, and also sprinting activate the wallrun, this lets the jumo key free to use, so we can make a jump off the wall feature, i hope you can get what im saying XD
I found if you use an *if statement* to check if your *Y velocity* is > 0 and use that to reduce gravity while only on a wall, you get a nice wall slide effect that only takes place after the apex of your jump which is only a few lines of code away from being a wall jump.
I'm new to coding, but, if I'm understanding dot products correctly, could you use a dot product between the camera (or character) direction and the wall normal to determine whether you slide on the wall or run along it?
Hello @Garbaj
Nice video, been following your channel because of your awesome short and informative videos about game play concepts. I just had a question on how I would make this into only some walls are allowed to wall run on. So far any wall that has a vertical face, you can wall run on. I have thought on using Collision Masks and layers but that gave me no luck, tried using Area nodes but still no luck, How could I achieve this?
This ought be a whole video in itself, but you could put certain off-limits walls into a “no run” group and using the same get_slide_collision() function, you can check if a wall is in that group or not and only climb on the walls that aren’t in that group
how can i make the character wall jump form the wall run?
I used raycasts and made gravity be a constant. The one thing that I did wrong though is the way it works. You don't stick to a wall. So when you look away, you fall.
Here's some code for my character, just in case anyone wants to see a different wall run technique:
extends KinematicBody
onready var camera = $Pivot/Camera
var gravity = -25
var jump_speed = 6
var max_speed = 6
var mouse_sensitivity = 0.008
var velocity = Vector3()
var jump = false
var can_w_run = true
var wall_running = false
var needs_rot = true
var needs_counter_rot = true
var can_use_timer = true
var wr_speed = 6
var needs_timer_two = true
var can_slide = true
var sliding = false
var needs_slide_rot = true
var needs_slide_counter_rot = true
var can_use_slide_timer = true
var slide_speed = 4
var pulling = false
func align_with_y(xform, new_y):
xform.basis.y = new_y
xform.basis.x = -xform.basis.z.cross(new_y)
xform.basis = xform.basis.orthonormalized()
return xform
func get_input():
jump = false
if Input.is_action_just_pressed("jump"):
jump = true
var input_dir = Vector3()
if Input.is_action_pressed("forward") or wall_running:
input_dir += -global_transform.basis.z
if Input.is_action_pressed("back") and !wall_running and !sliding:
input_dir += global_transform.basis.z
if Input.is_action_pressed("left") and !wall_running and !sliding:
input_dir += -global_transform.basis.x
if Input.is_action_pressed("right") and !wall_running and !sliding:
input_dir += global_transform.basis.x
input_dir = input_dir.normalized()
return input_dir
func _unhandled_input(event):
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
if !wall_running:
rotate_y(-event.relative.x * mouse_sensitivity)
elif wall_running:
$Pivot.rotate_y(-event.relative.x * mouse_sensitivity)
$Pivot.rotate_x(-event.relative.y * mouse_sensitivity)
$Pivot.rotation.x = clamp($Pivot.rotation.x, -1.2, 1.2)
func _physics_process(delta):
fall_recover()
if is_on_floor() and !can_w_run:
can_w_run = true
if not ($L_RayCast.is_colliding() or $R_RayCast.is_colliding()) or is_on_floor() or not can_w_run:
wall_running = false
elif is_on_wall() and can_w_run and not is_on_floor():
wall_running = true
if !wall_running:
velocity.y += gravity * delta
rotation.z = 0
$Pivot.rotation.y = 0
$Pivot.rotation.z = 0
if !sliding:
var desired_velocity = get_input() * max_speed
velocity.x = desired_velocity.x
velocity.z = desired_velocity.z
rotation.x = 0
if jump and is_on_floor():
velocity.y = jump_speed
elif sliding:
var slide_velocity = get_input() * slide_speed
velocity.x = slide_velocity.x
velocity.z = slide_velocity.z
elif wall_running:
var wallrun_velocity = get_input() * wr_speed
velocity.x = wallrun_velocity.x
velocity.z = wallrun_velocity.z
if can_use_timer:
$WR_Timer.start()
can_use_timer = false
if needs_rot:
if $L_RayCast.is_colliding():
var n = $L_RayCast.get_collision_normal()
global_transform = align_with_y(global_transform, n)
rotate_object_local(Vector3(0, 0, 1), PI/3)
needs_rot = false
if $R_RayCast.is_colliding():
var n = $R_RayCast.get_collision_normal()
global_transform = align_with_y(global_transform, n)
rotate_object_local(Vector3(0, 0, 1), -PI/3)
needs_rot = false
velocity.y = 0
if $WR_Timer.time_left == 0:
can_w_run = false
wall_running = false
can_use_timer = true
yield(get_tree().create_timer(0.8), "timeout")
can_w_run = true
needs_rot = true
needs_counter_rot = true
elif Input.is_action_just_pressed("jump"):
can_w_run = false
wall_running = false
can_use_timer = true
velocity.y = 10
if $L_RayCast.is_colliding():
velocity.x += 3
if $R_RayCast.is_colliding():
velocity.x += -3
yield(get_tree().create_timer(0.8), "timeout")
can_w_run = true
needs_rot = true
needs_counter_rot = true
elif not ($Front_L_RayCast.is_colliding() or $Front_R_RayCast.is_colliding()):
can_w_run = false
wall_running = false
can_use_timer = true
yield(get_tree().create_timer(0.8), "timeout")
can_w_run = true
needs_rot = true
needs_counter_rot = true
if is_on_floor() and Input.is_action_pressed("ui_down") and can_slide:
sliding = true
can_slide = false
if sliding:
if can_use_slide_timer:
$Slide_Timer.start()
can_use_slide_timer = false
if needs_slide_rot:
rotate_object_local(Vector3(1, 0, 0), PI/3)
needs_slide_rot = false
if $Slide_Timer.time_left == 0:
if needs_slide_counter_rot:
rotation.x = 0
needs_slide_counter_rot = false
yield(get_tree().create_timer(1), "timeout")
needs_slide_rot = true
needs_slide_counter_rot = true
can_use_slide_timer = true
can_slide = true
sliding = false
elif Input.is_action_just_released("ui_down"):
if needs_slide_counter_rot:
rotation.x = 0
needs_slide_counter_rot = false
yield(get_tree().create_timer(1), "timeout")
needs_slide_rot = true
needs_slide_counter_rot = true
can_use_slide_timer = true
can_slide = true
sliding = false
elif sqrt(pow(velocity.x, 2) + pow(velocity.z, 2)) == 0:
if needs_slide_counter_rot:
rotation.x = 0
needs_slide_counter_rot = false
yield(get_tree().create_timer(1), "timeout")
needs_slide_rot = true
needs_slide_counter_rot = true
can_use_slide_timer = true
can_slide = true
sliding = false
velocity = move_and_slide(velocity + get_floor_velocity() * 0.03, Vector3.UP, true)
func fall_recover():
if !is_on_floor() and !wall_running and velocity.y < 0:
if $Pull_Lower.is_colliding() and !$Pull_Upper.is_colliding():
pulling = true
if pulling:
velocity.y = 10
pulling = false
Some aspects of my code, such as the basic movement and the align_with_y function, came from the tutorials created by KidsCanCode.
A few necessary explanations regarding my code:
- It isn't strictly limited to wall running; some sections include fall recovery (grabbing onto ledges) and sliding. I decided to leave those in there in case anyone was interested.
- $L_RayCast and $R_RayCast are raycasts extending from the center of the player to one unit left and right, respectively. They are used to detect whether a wall is present for wall running.
- $Front_L_RayCast and $Front_R_RayCast are raycasts positioned about an arm's length in front of the player at about chest height and extending to the left and right, respectively. These determine (while wall running) whether there is enough space left to continue wall running. This is why you fall off of the wall if you are about to reach the end of it.
- $Pull_Lower is yet another raycast; this one is positioned at about eye level and points in the forward direction. $Pull_Upper is a duplicate of this raycast but is positioned slightly higher -- high enough that it is above the character mesh. These aid in fall recovery; if $Pull_Lower is colliding but $Pull_Upper is not, this essentially tells the physics engine, "There is a ledge (rather than a solid wall) for the player to grab onto."
- I know that the input side of my code gets a little cluttered. Long story short, if you're not wall running, the code checks for input on A, W, S, and D. If you are wall running, the code ignores input from the keys but behaves as though W is being held -- in other words, it assumes you want to move forward. This makes sense; moving sideways would cause you to either go inside the wall or fall off of it, and moving backwards would realistically mean losing momentum.
I know this is a lot, so just respond to this comment if you have any questions.
could you make a Wall-Jump tutorial? all i found is tutorial for 2d games
Wall runni-
HEY WHATS UP GAMERS!
Will there be a tutorial about ragdolls and animations?
And what about sliding? For example it is in apex legends.
Nice video! Keep it up!
GREAT Teacher this is AWESOME Thank you very much m'y friends and me Will ne very happys with this incredible present we Will do funiest GAMEs !!!
When trying to access the normal in "direction = -wall_normal.normal * speed", I get the error "Invalid access to property or key 'normal' on a base object of type 'KinematicCollision3D'." Does anyone know how to fix it?
Sir how to tilt camera while we are running on the walls?
I think we have to use viewports
Cool tutorial, but can you update it for 3.3.2?
why do i just start floating?
Bro you start to floating because you sholud use the velocity.y not Gravity
Hey can you make an updated version of this tutorial for the improved/Updated version of the FPS controller?
the buggy part in the beginning is because im just flying now haha
edit: partially fixed it. now you fall when not on the wall but i also want to make it so you can jump on the wall and go onto another
how do you add camera tilt to your wallrun???
How do i do the file repository thing in the beginning of your video
On the github page, click on the green "code" button and download zip. Extract the zip to any place on your computer, then go to your Godot project file folders and drag the files extracted from the zip into the godot project folder
How hard would it be to get a 3d player to run up a wall and upside down?
Climbing walls should be pretty easy to do since this tutorial gets you 90% of the way there, but going upside down would require a little more work.
Godot has functions to check if your character is clliding with a wall or the ceiling, so you can mess up with gravity quite easily I suppose.
can you make a tutorial for how to make the camera rotate based on the wall you stepping on? i wanna make the camera tilt based on what direction the wall is
If my computer worked I'd do this lol
oof
Nice vid, any chance you could release all of the tutorials' codes about FPS? (Wallrunning, crouching, jumping, etc)
You can find the source code for a lot of my tutorials here: www.github.com/GarbajYT
@@garbaj Thanks, if you get the time, could you make a stop sliding on slopes for 3.2 as well? Can't figure it out, hope you can.
so how could you change that time into like a stamina bar im sure its not much different in coding i guess you would have to create a stamina bar obviously then script a call to use that resorce till it runs out? like i get the general idea how that would work but not the exact scripting. im like beyond new and binge watching godot videos making things slowly stick
Is there a rotation pls reply i need it
if input = left or right and forward and not grounded and colliding with wall set timer.
timer = gravity + ? y
gravity = -y * time
if graviity is > 10 gravity = 10
could you please update this for youre improved fps controller for godot 3.2, as I have been trying to get this to work in the improved controller. But I just cant
Your tutorials are gold ! I love them !
In the future, it would be very great if you could figure out how to make a grapple gun in godot ! I search but for now, anything i made dont work :/
Stay tuned ;)
How to get collision info if body is rigid instead of kinematic
how could you do the camera tilt?
keep going man
Amazing vids!!
Can u plz make a tutorial on how to add the github to godot
This is cool and all but can you do wall jump tutorial
umm itn not working from first when i go to a wall my playerf sticks to ground and can jump
here is my code
extends KinematicBody
var speed
var default_speed = 15
var sprint_speed = 25
var h_acceleration = 8
var air_acceleration = 1
var normal_acceleration = 6
var gravity = 20
var jump = 7
var full_contact = false
var mouse_sensitivity = 0.05
var grappling = false
var hookpoint = Vector3()
var hookpoint_get = false
var direction = Vector3()
var h_velocity = Vector3()
var movement = Vector3()
var graviry_vec =Vector3()
var fall = Vector3()
onready var head =$head
onready var groundcheck = $groundcheck
onready var camera = $head/Camera
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _input(event):
if event is InputEventMouseMotion:
rotate_y(deg2rad(-event.relative.x * mouse_sensitivity))
head.rotate_x(deg2rad(-event.relative.y * mouse_sensitivity))
head.rotation.x = clamp(head.rotation.x, deg2rad(-89), deg2rad(89))
func wall_run():
if Input.is_action_pressed("jump"):
if Input.is_action_pressed("moce_forward"):
if is_on_wall():
fall.y = 0
func _physics_process(delta):
speed = default_speed
direction = Vector3()
if groundcheck.is_colliding():
full_contact = true
else:
full_contact = false
if not is_on_floor():
graviry_vec += Vector3.DOWN * gravity * delta
h_acceleration = air_acceleration
elif is_on_floor() and full_contact:
graviry_vec = -get_floor_normal() * gravity
h_acceleration = normal_acceleration
else:
graviry_vec = -get_floor_normal()
h_acceleration = normal_acceleration
if Input.is_action_just_pressed("jump") and (is_on_floor() or groundcheck.is_colliding()):
graviry_vec = Vector3.UP *jump
if Input.is_action_pressed("ability"):
speed = sprint_speed
wall_run()
if Input.is_action_pressed("moce_forward"):
direction -= transform.basis.z
elif Input.is_action_pressed("move_backward"):
direction += transform.basis.z
if Input.is_action_pressed("move_right"):
direction += transform.basis.x
elif Input.is_action_pressed("move_left"):
direction -= transform.basis.x
direction * direction.normalized()
h_velocity = h_velocity.linear_interpolate(direction * speed, h_acceleration * delta)
movement.z = h_velocity.z + graviry_vec.z
movement.x =h_velocity.x + graviry_vec.x
movement.y = graviry_vec.y
move_and_slide(movement, Vector3.UP)
What version of Godot did you use?
Bro please tell me how to get the normal in godot 4
Here is the code:
Direction = -Wall_normal.normal * Speed_current
thanks good stuff
How to make the camera tilt too?
i tried following this tutorial and the wall running never work for me
me neither did you manage to fix it?
We will make karlson
i tried this on your adanced fps controller. i just fricking float. if possible make a new wallrun tut so people dont have to mix all of the tutorials and get a glitchy mess
How do I load the tack file?
Tacn
Tscn
You need more subs
Ok i’ve almost done karlson In godot
With the grapling too
Make a video for bunnyhoping and surfing PLEASE!!!
Nice!!!
How to make free fire or pubg in godot?
it didnt work for me bro
I ran into a similar problem; it turns out that the problem was with the walls I was using.
@@yukmsacierzorro what kind of walls did you end up using?
NICE
Make some tutorials for android games please 🙃
I have no idea how to do that lol
Do the cross hair next pls
There are some videos I'd like to do before getting to the crosshair video, but stay tuned
Ok thanks
nice
hello fellow linux user
Your words are too small, you can make it bigger.
I keep forgetting to enlarge the text
I got click-baited. I wanted to learn how to hall for real.
Nice try .. will done but u can do better ...u must check out unity wall run and take some ideas...you can do that...
I love you. 💕 no homo
how do i import these?